"use strict";
/**
 * Клиентская библиотека для написания программ генерации G-кода на клиенте в редакторе
 */
define(function(){

    // Простой шаблонизатор
    function template(tpl, data){
        tpl = tpl.replace(new RegExp('\\{\\s*([\\w\\.]+)\\s*\\}', 'gm'), function(str, tag, offset, source){
            // Поддерживаются контейнеры с доступом к свойствам объекта { object.subobject.property }
            var steps = tag.split('.');
            var value = data;
            for(var i=0;i<steps.length;i++){
                value = value[steps[i]];
            }
            return value;
        });
        return tpl;
    };

    var _feed = 600;
    var _g_code = [];
    var _data = {};     // Последние накопленные данные по координатам и подаче
    var _paths = {};    // Список именованных путей (массивов координат)
    var _size = {x:0, y:0, z:0};

    return {

        init: function() {
            _feed   = 600;
            _g_code = [];
            _data   = {};
            _paths  = {};
            _size   = {x:0, y:0, z:0};
        },

        size: function(_x, _y, _z){ _size = {x:_x, y:_y, z:_z}; },

        x: function(value) { return this.clamp(value, 0, _size.x); },
        y: function(value) { return this.clamp(value, 0, _size.y); },
        z: function(value) { return value; },

        // Ограничение числа в интервале от min до max
        clamp: function(value, min, max) {
            value = Math.max(min, value);
            value = Math.min(value, max);
            return value;
        },

        // Ограничение по имени оси
        _clamp: function(axis, value) {
            if(axis == 'x') return this.x(value);
            if(axis == 'y') return this.y(value);
            if(axis == 'z') return this.z(value);
            return value;
        },

        // Задание текущей подачи
        feed: function(val){
            if(val !== undefined) _feed = val;
            return _feed;
        },

        // Задание именованной кривой (массив точек)
        path: function(name, steps) {
            if(steps !== undefined){
                _paths[name] = steps;
            }
            else {
                if( _paths[name] === undefined){
                    throw new Error("No path with name '" + name + "' defined!");
                }
            }
            var _ = {
                steps: (idx)=>{
                    if (idx === undefined)
                        return _paths[name] !== undefined ? _paths[name] : [];
                    else
                        if (_paths[name] === undefined) return null;
                        else return _paths[name][idx];
                },
                forward: (cb)=>{ for(var i=0; i<_paths[name].length; i++) cb(_paths[name][i]); return this; },
                backward: (cb)=>{ for(var i=_paths[name].length-1; i>=0; i--) cb(_paths[name][i]); return this; }
            };
            return _;
        },

        // Добавление смещения к данным
        offset: function(data, offset) {
            var res = {...data};
            for (var v in offset) if(res[v] !== undefined) res[v] = this._clamp(v, res[v] + offset[v]);
            return res;
        },

        // Добавление команды в G-код по заданному шаблону tpl с заполнением данными из data.
        // Если data не задано, то в задание помещается сразу строка.
        push: function(tpl, data, options){
            if(data === undefined) {
                _g_code.push(tpl);
            }
            else {
                if(options !== undefined) {
                    if(options.offset !== undefined) data = this.offset(data, options.offset);
                }
                // TODO: Проверка на повторение данных. Дублирующиеся данные можно не добавлять, т.к. станок их не исполнит
                _data = {..._data, ...data}; // Накладываем новые данные и кэшируем их
                _g_code.push(template(tpl, _data));
            }
            return this;
        },

        //  Получение текстового представления программы
        gcode: function() {
            return _g_code.join('\n');
        }
    };
});
